﻿// <copyright file="ProductKeyManagerXmlHandler.cs" company="Snowman Consulting">
//     Copyright (c) 2009 Snowman Consulting. All rights reserved.
// </copyright>

namespace SnowmanConsulting.ProductKeyManager.Xml
{
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.IO;
    using System.Linq;
    using System.Xml.Linq;
    using SnowmanConsulting.ProductKeyManager.Data;

    /// <summary>
    /// Xml Handler for Products Key Manager Xml
    /// </summary>
    public class ProductKeyManagerXmlHandler : IXmlHandler
    {
        /// <summary>
        /// products collection
        /// </summary>
        private ProductCollection products;

        /// <summary>
        /// generated xml
        /// </summary>
        private string generatedXml;

        /// <summary>
        /// Gets the Products imported from the XML.
        /// </summary>
        /// <value>The Products.</value>
        public ProductCollection Products
        {
            get { return this.products; }
            private set { this.products = value; }
        }

        /// <summary>
        /// Gets the XML generated by from the Products.
        /// </summary>
        /// <value>The generated XML.</value>
        public string GeneratedXml
        {
            get { return this.generatedXml; }
            private set { this.generatedXml = value; }
        }

        /// <summary>
        /// Imports the XML.
        /// </summary>
        /// <param name="xml">The XML string.</param>
        public void Load(string xml)
        {
            XDocument document = XDocument.Load(new StringReader(xml));
            this.Load(document);
        }

        /// <summary>
        /// Imports the XML.
        /// </summary>
        /// <param name="fileUri">The file URI.</param>
        public void Load(Uri fileUri)
        {
            XDocument document = XDocument.Load(fileUri.ToString());
            this.Load(document);
        }

        /// <summary>
        /// Imports the XML.
        /// </summary>
        /// <param name="xmlDocument">The XML document.</param>
        public void Load(XDocument xmlDocument)
        {
            int version = 1;

            try
            {
                XElement versionElement = xmlDocument.Descendants("ProductKeys").First();
                version = Int32.Parse(versionElement.Attribute("version").Value, CultureInfo.InvariantCulture);
            }
            catch (InvalidOperationException) 
            {
            }
            catch (NullReferenceException) 
            {
            }

            switch (version)
            {
                case 1:
                default:
                    this.LoadVersion1(xmlDocument);
                    break;
            }
        }

        /// <summary>
        /// Imports the XML version 1.
        /// </summary>
        /// <param name="xmlDocument">The XML document.</param>
        private void LoadVersion1(XDocument xmlDocument)
        {
            this.Products = new ProductCollection();

            IEnumerable<XElement> productElements = xmlDocument.Descendants("Product");

            foreach (XElement productElement in productElements)
            {
                Product product;

                string name = string.Empty;
                string notes = string.Empty;
                string icon = string.Empty;
                string category = string.Empty;

                XAttribute nameAttribute = productElement.Attribute("Name");
                if (nameAttribute != null)
                {
                    name = nameAttribute.Value;
                }
                else
                {
                    continue;
                }

                XAttribute notesAttribute = productElement.Attribute("Notes");
                if (notesAttribute != null)
                {
                    notes = notesAttribute.Value;
                }

                XAttribute iconAttribute = productElement.Attribute("Icon");
                if (iconAttribute != null)
                {
                    icon = iconAttribute.Value;
                }

                XAttribute categoryAttribute = productElement.Attribute("Category");
                if (categoryAttribute != null)
                {
                    category = categoryAttribute.Value;
                }

                product = new Product
                {
                    Name = name,
                    Notes = notes,
                    Icon = ProductIconHelper.CreateProductIcon(icon),
                    Category = category
                };

                this.Products.Add(product);

                try
                {
                    IEnumerable<XElement> keyElements = productElement.Descendants("Key");

                    foreach (XElement keyElement in keyElements)
                    {
                        ProductKey key;
                        string keyCode = string.Empty;
                        string keyNotes = string.Empty;
                        string keyAllocatedTo = string.Empty;

                        XAttribute keyCodeAttribute = keyElement.Attribute("KeyCode");
                        if (keyCodeAttribute != null)
                        {
                            keyCode = keyCodeAttribute.Value;
                        }

                        XAttribute keyNotesAttribute = keyElement.Attribute("Notes");
                        if (keyNotesAttribute != null)
                        {
                            keyNotes = keyNotesAttribute.Value;
                        }

                        XAttribute keyAllocatedToAttribute = keyElement.Attribute("AllocatedTo");
                        if (keyAllocatedToAttribute != null)
                        {
                            keyAllocatedTo = keyAllocatedToAttribute.Value;
                        }

                        key = new ProductKey
                        {
                            Code = keyCode,
                            Notes = keyNotes,
                            AllocatedTo = keyAllocatedTo
                        };

                        product.Keys.Add(key);
                    }
                }
                catch (InvalidOperationException) 
                {
                }
                catch (NullReferenceException)
                {
                }
            }
        }

        /// <summary>
        /// Generates the XML.
        /// </summary>
        /// <param name="productCollection">The Products.</param>
        public void GenerateXml(ProductCollection productCollection)
        {
            this.GenerateXml(productCollection, false, string.Empty);
        }

        /// <summary>
        /// Generates the XML.
        /// </summary>
        /// <param name="productCollection">The Products.</param>
        /// <param name="generateStyleSheet">if set to <c>true</c> the stylesheet is generated.</param>
        /// <param name="fileName">Name of the file.</param>
        public void GenerateXml(ProductCollection productCollection, bool generateStyleSheet, string fileName)
        {
            string xmlResult = "<?xml version=\"1.0\" standalone=\"yes\" ?>" + Environment.NewLine;
            if (generateStyleSheet && !String.IsNullOrEmpty(fileName))
            {
                xmlResult += "<?xml-stylesheet type=\"text/xsl\" href=\"" + fileName + ".xsl\"?>" + Environment.NewLine;
            }

            XElement xml = new XElement(
                "ProductKeys",
                new XAttribute("version", 1),
                GenerateProductElements(productCollection));

            this.GeneratedXml = xmlResult + xml.ToString();
        }

        /// <summary>
        /// Generates the product elements.
        /// </summary>
        /// <param name="productCollection">The product collection.</param>
        /// <returns>IEnumerable list of product XElements</returns>
        private static IEnumerable<XElement> GenerateProductElements(ProductCollection productCollection)
        {
            return from p in productCollection
                   select new XElement(
                       "Product",
                       new XAttribute("Name", p.Name),
                       new XAttribute("Notes", string.IsNullOrEmpty(p.Notes) ? string.Empty : p.Notes),
                       new XAttribute("Category", string.IsNullOrEmpty(p.Category) ? string.Empty : p.Category),
                       new XAttribute("Icon", p.Icon == null ? string.Empty : p.Icon.IconUrl),
                       GenerateProductKeyElements(p));
        }

        /// <summary>
        /// Generates the product key elements.
        /// </summary>
        /// <param name="product">The product.</param>
        /// <returns>IEnumerable list of product key XElements</returns>
        private static IEnumerable<XElement> GenerateProductKeyElements(Product product)
        {
            return from k in product.Keys
                   select new XElement(
                       "Key",
                       new XAttribute("KeyCode", k.Code),
                       new XAttribute("AllocatedTo", string.IsNullOrEmpty(k.AllocatedTo) ? string.Empty : k.AllocatedTo));
        }
    }
}
